/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ComMestre;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import SqlDatabase.SqlDatabase;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 *
 * @author Du
 */
public class Mestre implements Runnable {

    private ServerSocket mestre;
    private Socket conNo;
    private InputStream in;
    private OutputStream out;
    private int servPort;
    private SqlDatabase bd;

    public Mestre(int servPort) throws IOException, ClassNotFoundException, SQLException {
        this.servPort = servPort;
        mestre = new ServerSocket(servPort);
        this.bd = new SqlDatabase();
    }

    public void setconNo(Socket sock) {
        conNo = sock;
    }

    public ServerSocket getServSocket() {
        return mestre;
    }

    @Override
    public synchronized void run() {
        try {
            in = conNo.getInputStream();     //recebe mensagem cliente
            out = conNo.getOutputStream();   //envia resposta para cliente

            String entrada = new String();             //string para receber o nome do arquivo
            int opcao = 1;
            Scanner scan = new Scanner(in);
            PrintStream envia = new PrintStream(out);
            //recebe a opção da operação a ser realizada
            if (scan.hasNext()) {
                opcao = Integer.parseInt(scan.nextLine());
            }

            //recebe o nome do arquivo
            if (scan.hasNext()) {
                entrada = scan.nextLine();
            }

            if (opcao == 1) { //opcao de copiar arquivo
                if (bd.exists(entrada)) {

                    // lê o nó do cliente para efetuar a copia
                    String clientcopia = new String();
                    if (scan.hasNext()) {
                        clientcopia = scan.nextLine();
                    }
                    //procurar o arquivo no BD e recuperar o tamanho e o host do arquivo
                    List<String> files;
                    files = bd.searchCopy(entrada);
                    //gera um valor aleatorio entre 0-tamanho da lista de copias
                    Random gerador = new Random();
                    int numero = gerador.nextInt(files.size());
                    while (clientcopia.equalsIgnoreCase(files.get(numero))) {
                        numero = gerador.nextInt(files.size());
                    }
                    //o numero gerado será o indice do cliente armazenado na Lista
                    bd.setFlag(entrada, files.get(numero), "r");
                    // passa o nó da maquina onde esta o arquivo
                    String end = files.get(numero);
                    // passa o tamanho do arquivo
                    int tamArq = bd.getSize(entrada);
                    //cria copia no bd
                    bd.createCopy(entrada, clientcopia);
                    // envia as informações para o cliente
                    envia.println("1");
                    envia.println(end);
                    envia.println(String.valueOf(tamArq));

                    System.out.println("\nArquivos no BD:");
                    bd.showFiles();
                    System.out.println("\nCopias do BD:");
                    bd.showCopies();
                    System.out.println("\n");

                    bd.setFlag(entrada, files.get(numero), "-");

                    System.out.println("\nArquivos no BD:");
                    bd.showFiles();
                    System.out.println("\nCopias do BD:");
                    bd.showCopies();
                    System.out.println("\n");
                } else {
                    envia.println("0");
                }
            } else if (opcao == 2) {  //opcao de excluir arquivos
                //Mestre deve verificar se o arquivo não existe, se sim retorna 0, 1 caso contrário
                if (!bd.exists(entrada)) {
                    envia.println("0");
                } else {
                    envia.println("1");
                }
                List<String> files;
                files = bd.searchCopy(entrada);

                //exclui do BD
                if (bd.getFlag(entrada).equalsIgnoreCase("-")) {
                    bd.delete(entrada);
                } else if (bd.getFlag(entrada).equalsIgnoreCase("r")) {
                    while (bd.countCopiesBeingRead(entrada) > 0) {
                        continue;
                    }
                    //bd.delete("doc_duplicate.txt");
                } else {
                    System.out.println("Impossivel deletar: arquivo " + entrada + " sendo escrito");
                }

                //Laço para excluir todas as copias do arquivo
                for (int i = 0; i < files.size(); i++) {
                    Socket clnt = new Socket(files.get(i), servPort);
                    OutputStream ops = clnt.getOutputStream();
                    PrintStream ps = new PrintStream(ops);
                    //envia código de mestre ao nó que possui o arquivo para deletá-lo
                    ps.println("2");
                    //envia o nome do arquivo a ser deletado
                    ps.println(entrada);
                    ps.flush();
                    ps.close();
                    bd.deleteCopy(entrada, files.get(i));
                }
                envia.println("1");
                System.out.println("\nArquivos no BD:");
                bd.showFiles();
                System.out.println("\nCopias do BD:");
                bd.showCopies();
                System.out.println("\n");

            } else if (opcao == 3) {  //opcao de criar arquivos
                if (bd.exists(entrada)) {
                    envia.println("0");
                } else {
                    envia.println("1");
                }

                String nArq = new String();
                int tamArq = 0;
                String nomeNo = new String();
                //recebe nome do arquivo
                if (scan.hasNext()) {
                    nArq = scan.nextLine();
                }
                //recebe o tamanho do arquivo
                if (scan.hasNext()) {
                    tamArq = Integer.parseInt(scan.nextLine());
                }
                //recebe o nome do nó que está criando o arquivo
                if (scan.hasNext()) {
                    nomeNo = scan.nextLine();
                }
                //cria a tupla no banco de dados
                bd.create(nArq, tamArq, nomeNo);
                System.out.println("\nArquivos no BD:");
                bd.showFiles();
                System.out.println("\nCopias do BD:");
                bd.showCopies();
                System.out.println("\n");

            } else if (opcao == 4) {                //atualiza o arquivo
                if (bd.exists(entrada)) {
                    envia.println("1");
                    String nArq = new String();
                    int tamArq = 0;
                    String nomeNo = new String();

                    //recebe nome do arquivo
                    if (scan.hasNext()) {
                        nArq = scan.nextLine();
                    }
                    //recebe o tamanho do arquivo
                    if (scan.hasNext()) {
                        tamArq = Integer.parseInt(scan.nextLine());
                    }
                    //recebe o nome do nó que está atualizando o arquivo
                    if (scan.hasNext()) {
                        nomeNo = scan.nextLine();
                    }
                    List<String> files;
                    files = bd.searchCopy(entrada);
                    
                    bd.updateDateM(nomeNo);
                    
                    bd.updateSize(nArq, tamArq);
                    
                    System.out.println("\nArquivos no BD:");
                    bd.showFiles();
                    
                    System.out.println("\nCopias do BD:");
                    bd.showCopies();
                    
                    System.out.println("\n");

                    for (int i = 0; i < files.size(); i++) {
                        Socket clnt = new Socket(files.get(i), servPort);
                        OutputStream ops = clnt.getOutputStream();
                        PrintStream ps = new PrintStream(ops);
                        //envia código de mestre ao nó que possui o arquivo para atualizá-lo
                        ps.println("3");
                        //envia o nome do arquivo a ser atualizado
                        ps.println(entrada);
                        ps.println(nomeNo);
                        ps.println(bd.getSize(entrada));
                        ps.flush();
                        ps.close();
                        
//                        InputStream in2 = clnt.getInputStream();
//                        Scanner scan2 = new Scanner(in2);
//                        String nomeArq = new String();
//                        String host = new String();
//                        int tamanhoArq = 0;
//                        
//                        if(scan2.hasNext()){
//                            nomeArq = scan2.nextLine();
//                        }
//                        if(scan2.hasNext()){
//                            tamanhoArq = Integer.parseInt(scan2.nextLine());
//                        }
//                        if(scan2.hasNext()){
//                            host = scan2.nextLine();
//                        }
//                        bd.deleteCopy(host, nArq);
//                        bd.create(nomeArq, tamanhoArq, host);
                        
                    }
                    
                    
                } else {
                    envia.println("0");
                }
            }else if (opcao == 5) {  //opcao de informar
                String nomeArq = new String();
                int tamArq = 0;
                String nomeHost = new String();

                for (int i = 0; i < Integer.parseInt(entrada); i++) {
                    //recebe o nome do arquivo
                    if (scan.hasNext()) {
                        nomeArq = scan.nextLine();
                    }
                    //recebe o tamanho do arquivo
                    if (scan.hasNext()) {
                        tamArq = Integer.parseInt(scan.nextLine());
                    }
                    //recebe o nome do host do arquivo
                    if (scan.hasNext()) {
                        nomeHost = scan.nextLine();
                    }

                    if (bd.exists(nomeArq)) {
                        if (bd.existsCopy(nomeArq, nomeHost)) {
                            envia.println("2");
                        }
                        bd.createCopy(nomeArq, nomeHost);
                    } else {
                        //cria a tupla no banco de dados
                        bd.create(nomeArq, tamArq, nomeHost);
                    }
                    envia.println("1");

                }
                System.out.println("\nArquivos no BD:");
                bd.showFiles();
                System.out.println("\nCopias do BD:");
                bd.showCopies();
                System.out.println("\n");
            } else { //caso nenhum seja escolhida
            }


            envia.flush();
            in.close();
            out.close();
            envia.close();
            conNo.close();
        } catch (IOException ex) {
            Logger.getLogger(Mestre.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
